<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>defineProperty和forEach</title>
</head>
<body>
  <h1>打开控制台</h1>
  <script>

    // Object.defineProperty() 方法会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象。
    // Object.defineProperty(obj, key, {
    //   // value: '',  // 属性对应的值。可以是任何有效的JavaScript值:数值，对象，函数等，默认为: undefined
    //   // configurable: true, // 是否可以配置对象，删除属性，默认：false
    //   // writable: true, // 是否可以修改对象，默认：false
    //   // enumerable: true, // 是否可以枚举，默认：false
    //   get() { // 属性的 getter 函数，如果没有 getter，则为 undefined
    //     // 将watcher添加到订阅事件中 
    //     return value;
    //   },
    //   set(newValue) { // 属性的 setter 函数，如果没有 setter，则为 undefined
    //     // 如果值没有发生改变则忽略
    //     if(value === newValue) return; 
    //     value = newValue; // 设置最新的值
    //   },
    // });


    // var o = {}; // 创建一个新对象
    // Object.defineProperty(o, 'a', {
    //   value: 22,
    //   writable: false,
    // });
    // console.log(o.a); // 22
    // o.a = 25; // 不会报错(在严格模式下会报错)
    // console.log(o.a); // 22

    // // 严格模式
    // (function() {
    //   'use strict';
    //   var o = {};
    //   Object.defineProperty(o, 'b', {
    //     value: 22,
    //     writable: false,
    //   });
    //   o.b = 3; // 报错: Cannot assign to read only property 'b' of object
    //   return o.b; // 22
    // }());


    // var o = {};
    // Object.defineProperty(o, 'a', {
    //     value : 1,
    //     enumerable: true,
    // });
    // Object.defineProperty(o, 'b', {
    //     value : 2,
    //     enumerable: false,
    // });
    // Object.defineProperty(o, 'c', {
    //     value : 3,
    //     // enumerable默认为false
    // });
    // o.d = 4; // 如果使用直接赋值的方式创建对象的属性，enumerable为true
    // // 等同于：
    // Object.defineProperty(o, 'd', {
    //   value: 4,
    //   writable: true,
    //   configurable: true,
    //   enumerable: true
    // });

    // for (var i in o) {
    //   console.log(i); // a d
    // }
    // console.log(Object.keys(o)); // ['a', 'd']

    // var p = { ...o }
    // console.log(p.a, p.b, p.c, p.d) // 1 undefined undefined 4


    // var o = {};
    // Object.defineProperty(o, 'a', {
    //   get() { return 1 },
    //   configurable: false,
    // });

    // Object.defineProperty(o, 'a', {
    //   configurable: true, // Cannot redefine property: a
    // });
    // Object.defineProperty(o, 'a', {
    //   enumerable: true, // Cannot redefine property: a
    // });
    // Object.defineProperty(o, 'a', {
    //   set() {}, // Cannot redefine property: a
    // });
    // Object.defineProperty(o, 'a', {
    //   get() { return 1 }, // Cannot redefine property: a
    // });
    // Object.defineProperty(o, 'a', {
    //   value: 12, // Cannot redefine property: a
    // });

    // console.log(o.a); // 1
    // delete o.a; // 不报错
    // console.log(o.a); // 1


    // [1,2,3].forEach(item => {
    //   console.log(item); // 1 2 3
    // });
    // [1, 2, 3].forEach.call(['a', 'b', 'c'], item => {
    //   console.log(item); // a b c
    // });


    // const data = {
    //   name: 'lzx',
    //   age: 22,
    //   sex: '男',
    //   address: { province: '江西省', city: '赣州市', area: '大余县' },
    //   infos: {
    //     likes: { one: '看书', two: '看电视' },
    //     specialtys: ['打球', '游泳'],
    //   },
    //   educations: [
    //     { school: '池江中学' },
    //     { school: '大余中学' },
    //   ],
    // };
    // // // 给定一个关联数组 ['address', 'city'] 如何获取实际值?(实际上就是data.address.city的值)
    // // // const arr1 = ['address', 'city']; --> 赣州市
    // // // 问题1：['infos', 'likes', 'one'] ?
    // // const arr1 = ['infos', 'likes', 'one'];
    // // // 问题2：['infos', 'specialtys', '1'] ?
    // // const arr2 = ['infos', 'specialtys', '1'];
    // // // 问题3：['educations', '0', 'school'] ?
    // // const arr3 = ['educations', '0', 'school'];

    // // // 方法一(for循环 in|of )
    // // let value1 = data; // 定义实际值
    // // // for(let i in arr1) {
    // // //   const key = arr1[i];
    // // //   value1 = value1[key];
    // // // }
    // // for(let key of arr1) {
    // //   value1 = value1[key];
    // // }
    // // console.log(value1); // 看书

    // // // 方法二(forEach)
    // // let value2 = data;
    // // arr2.forEach(key => value2 = value2[key]);
    // // console.log(value2); // 游泳

    // // // 方法三(reduce)
    // // let value3 = data;
    // // value3 = arr3.reduce((val, key) => val[key], value3);
    // // console.log(value3); // 池江中学

    // // 给定一个关联数组 ['educations', '0', 'school']和value 如何改变原对象实际值为value?(实际上就是改变data.educations[0].school的值)
    // const arr4 = ['educations', '0', 'school'];
    // const newData = arr4.reduce((val, key, index) => {
    //   if (index === arr4.length - 1) {
    //     return val[key] = '测试中学';
    //   };
    //   return val[key];
    // }, data);
    // console.log(data); // 变成了测试中学

    // let arr5 = [
    //   { name: 'lzx1', age: 1 },
    //   { name: 'lzx2', age: 2 },
    //   { name: 'lzx3', age: 2 },
    // ];

    // arr5.map((item) => {
    //   return {...item, age: 8 }; // 未变
    // });
    // // arr5.map(item => {
    // //   item.age = 8;
    // //   return item; // 改变
    // // });

    // console.log(arr5);

  </script>
</body>
</html>